package com.grace.web.controller.server;

import java.io.IOException;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;

import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import com.grace.common.annotation.Log;
import com.grace.common.core.controller.BaseController;
import com.grace.common.core.domain.AjaxResult;
import com.grace.common.core.page.TableDataInfo;
import com.grace.common.enums.BusinessType;
import com.grace.common.enums.GraceServerRoot;
import com.grace.common.exception.file.FileSizeLimitExceededException;
import com.grace.common.exception.file.InvalidExtensionException;
import com.grace.common.exception.job.TaskException;
import com.grace.common.utils.DateUtils;
import com.grace.common.utils.file.MimeTypeUtils;
import com.grace.mail.domain.MailTypeEnums;
import com.grace.mail.domain.MailUsedEnums;
import com.grace.mail.domain.OlyMail;
import com.grace.mail.domain.properties.EmailProperties;
import com.grace.mail.service.IOlyMailService;
import com.grace.oss.service.impl.NativeOssHandler;
import com.grace.quartz.domain.SysJob;
import com.grace.quartz.service.ISysJobService;
import com.grace.quartz.util.CronUtils;
import com.grace.system.service.impl.SysConfigServiceImpl;

/**
 * 邮件Controller
 * 
 * @author hush
 * @date 2021-03-06
 */
@RestController
@RequestMapping("/server/mail")
public class MailServerController extends BaseController {

    @Autowired
    private IOlyMailService olyMailService;

    @Autowired
    private NativeOssHandler ossHandler;

    @Autowired
    private SysConfigServiceImpl sysConfigService;

    @Autowired
    private ISysJobService jobService;

    /**
     * 查询邮件列表
     */
    @PreAuthorize("@ss.hasPermi('server:mail:list')")
    @GetMapping("/list")
    public TableDataInfo list(OlyMail olyMail) {
        startPage();
        List<OlyMail> list = olyMailService.selectOlyMailList(olyMail);
        return getDataTable(list);
    }

    /**
     * 获取邮件详细信息
     */
    @PreAuthorize("@ss.hasPermi('server:mail:query')")
    @GetMapping(value = "/{mailId}")
    public AjaxResult getInfo(@PathVariable("mailId") Long mailId) {
        return success(olyMailService.selectOlyMailById(mailId));
    }

    /**
     * 新增邮件
     */
    @PreAuthorize("@ss.hasPermi('server:mail:add')")
    @Log(title = "邮件", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@RequestBody OlyMail olyMail) {
        olyMail.setCreateBy(getUsername());
        return toAjax(olyMailService.insertOlyMail(olyMail));
    }

    /**
     * 修改邮件
     */
    @PreAuthorize("@ss.hasPermi('server:mail:edit')")
    @Log(title = "邮件", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult edit(@RequestBody OlyMail olyMail) {
        if (olyMail.getMailId() != null) {
            deleteOnTimeSend(olyMail.getMailId());
        }
        return toAjax(olyMailService.updateOlyMail(olyMail));
    }

    /**
     * 删除邮件
     */
    @PreAuthorize("@ss.hasPermi('server:mail:remove')")
    @Log(title = "邮件", businessType = BusinessType.DELETE)
    @DeleteMapping("/{mailIds}")
    public AjaxResult remove(@PathVariable Long[] mailIds) {
        int re = olyMailService.deleteOlyMailByIds(mailIds);
        for (Long mailId : mailIds) {
            deleteOnTimeSend(mailId);
        }
        return toAjax(re);
    }

    /**
     * 修改保存参数配置 通过key批量保存 默认设置为字符串类型
     */

    @Log(title = "邮件管理", businessType = BusinessType.UPDATE)
    @PostMapping("/updateConfig")
    @PreAuthorize("@ss.hasPermi('server:mail:config')")
    public AjaxResult updateConfig(@RequestBody Map<String, Object> mp) {
        mp.put("configGroup", EmailProperties.GROUP_NAME.getValue());
        int num = sysConfigService.updatesByMap(mp, getUsername());
        olyMailService.clearMailCache();
        return toAjax(num);
    }

    /**
     * 发送邮件邮件
     * 
     * @throws TaskException
     * @throws SchedulerException
     */
    @Log(title = "邮件管理", businessType = BusinessType.INSERT)
    @PostMapping("/send")
    @PreAuthorize("@ss.hasPermi('server:mail:send')")
    @ResponseBody
    public AjaxResult send(@RequestBody OlyMail olyMail, @RequestBody Map<String, Object> params)
            throws SchedulerException, TaskException {
        olyMail.setMailType(MailTypeEnums.HTML_MAIL.ordinal());
        olyMail.setMailUsed(MailUsedEnums.NORMAL.ordinal());
        if (olyMail.getSendTime() != null) {
            return sendOnTime(olyMail, params);
        }
        olyMailService.send(olyMail, params);
        return success();
    }

    private AjaxResult sendOnTime(OlyMail olyMail, Map<String, Object> params)
            throws SchedulerException, TaskException {
        SysJob sysJob = new SysJob();
        // 默认组
        sysJob.setJobGroup("DEFAULT");
        // 禁用并发
        sysJob.setConcurrent("1");
        // 执行策略 一次
        sysJob.setMisfirePolicy("2");
        // cron 表达式
        sysJob.setCronExpression(DateUtils.getCron(olyMail.getSendTime()));
        // 目标方法
        sysJob.setInvokeTarget("mailTask.onTimeSend(" + olyMail.getMailId() + "L)");
        if (validateJob(sysJob)) {
            // 已经存在Id 执行更新操作
            if (olyMail.getMailId() != null) {
                // 更新邮件记录
                olyMail.setUpdateBy(getUsername());
                olyMailService.updateOlyMail(olyMail);
                SysJob sp = new SysJob();
                // 任务名称
                sysJob.setJobName("sendMail_" + olyMail.getMailId() + "T");
                // 目标方法
                sysJob.setInvokeTarget("mailTask.onTimeSend(" + olyMail.getMailId() + "L)");
                // 获取是否存在任务
                sp.setJobName(sysJob.getJobName());
                List<SysJob> list = jobService.selectJobList(sp);
                // 任务不存在直接插入任务
                if (list == null || list.size() == 0) {
                    sysJob.setCreateBy(getUsername());
                    jobService.insertJob(sysJob);
                } // 任务存在直接更新
                else if (list.size() == 1) {
                    sp = list.get(0);
                    sp.setCronExpression(sysJob.getCronExpression());
                    sp.setUpdateBy(getUsername());
                    // 更新定时邮件,强制更新与默认参数一样
                    jobService.updateJob(sp);
                } else {
                    return AjaxResult.error("任务名可能作为其它任务前缀!");
                }

            } else {
                olyMail.setCreateBy(getUsername());
                // 插入邮件记录
                olyMailService.insertOlyMail(olyMail);
                // 目标方法
                sysJob.setJobName("sendMail_" + olyMail.getMailId() + "T");
                // 目标方法
                sysJob.setInvokeTarget("mailTask.onTimeSend(" + olyMail.getMailId() + "L)");
                sysJob.setCreateBy(getUsername());
                jobService.insertJob(sysJob);
            }
            // 状态正常
            sysJob.setStatus("0");
            jobService.changeStatus(sysJob);
            return success("任务已经添加或者已经修改！");
        } else {
            return AjaxResult.error("cron表达式转换失败！");
        }
    }

    public boolean validateJob(@Validated SysJob job) throws SchedulerException, TaskException {
        if (!CronUtils.isValid(job.getCronExpression())) {
            return false;
        }
        return true;
    }

    /**
     * 上传附件
     * 
     * @param multipartFile
     * @return
     * @throws IOException
     * @throws InvalidExtensionException
     * @throws FileSizeLimitExceededException
     */
    @PostMapping("/uploadAttach")
    @ResponseBody
    public AjaxResult uploadAttach(MultipartFile file)
            throws IOException, FileSizeLimitExceededException, InvalidExtensionException {
        return success(
                ossHandler.ossAppointUpload(file, GraceServerRoot.MAIL_DIR, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION));
    }

    /**
     * 检查附件
     * 
     * @param multipartFile
     * @return
     * @throws IOException
     */
    @PostMapping("/checkAttach")
    @ResponseBody
    public AjaxResult checkAttach(String attachKey) throws IOException {
        if (Paths.get(GraceServerRoot.MAIL_DIR.getWorkRoot(attachKey)).toFile().isFile()) {
            return success();
        }
        return AjaxResult.error();
    }

    @GetMapping("/test")
    @ResponseBody
    public AjaxResult test() {
        olyMailService.testConnection();
        return success();
    }

    /**
     * 删除定时任务
     * 
     * @param mailId
     */
    private void deleteOnTimeSend(Long mailId) {
        SysJob job = new SysJob();
        job.setJobName("sendMail_" + mailId + "T");
        List<SysJob> list = jobService.selectJobList(job);
        if (list != null && list.size() == 1) {
            try {
                jobService.deleteJob(list.get(0));
            } catch (SchedulerException e) {

            }
        }
    }

}
